home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
MENU_UTL
/
TPPDMENU
/
TPPDMENU.DOC
< prev
next >
Wrap
Text File
|
1990-01-11
|
20KB
|
482 lines
TPPDMENU.PAS 11:38:21 PM Jan 11, 1990
Pull down menus for Turbo Pascal Applications
Copyright August 1989, January 1990 -- Ken Henderson
Lots of libraries and routines have been developed in order to
give the pascal programmer the sleekness of pull down menus in
his applications. This is no exception. This one differs in
that no code is generated, the menus are file based and as such
are very flexible. You can keep the menu data in binary .MNU
files, you can build it into your applications -- whatever you
want. The actual invocation of the menus only requires one line
of code and is the same regardless of the contents of the menus.
Based in part on the editor toolbox menus and requiring the Turbo
Professional library of routines from TurboPower Software, these
menus offer unmatched flexibility and speed. The process, simply
put, is: you create a menu data file, compile it with the
supplied menu compiler, and reference it from within your
application -- that's all there is to it -- and there you have it
-- pull down menus that are both flexible and incredibly fast.
The question arises: "If I have Turbo Professional, why would I
need your pull down menus unit? TPMENU suits me just fine."
Well, you indeed might not need this unit if you have Turbo
Professional and TPMENU. I use this unit because a) I can change
the menus without recompiling the code that uses them b) I like
to distribute the menu source and compiler with my applications
so that my users can modify the menus if they like (to change the
trigger keys, etc.) and c) because these menus only require two
calls to initialize and invoke the menus. I love the Turbo
Professional stuff and you might not need this unit. If you
think you might, read on.
The first step in using TPPDMENU is to build the menu data file
on which the menus are based. This is simple and will be covered
later. The second step is to call the initialization routine
from within your program. It has the form:
Function InitMenus(MenuName : String; ColorTable : MenuAttributeArray;
UserDefinedHelpPtr,
UserDefinedValidationPtr,
UserDefinedEvaluatePtr,
UserDefinedExitMenusPtr,
BuiltInMenuAddress : Pointer) : Integer;
Menuname is the name of the file containing the menu data, pass
an empty string if you are using built-in data (covered below).
Calling InitMenus with the name of a menu file would go something
like this:
InitMenus('MYMENUS.MNU',MenuColors,nil,nil,nil,nil,nil);
ColorTable is the table of colors to be used by TPPDMENU when
displaying the menus. You will probably want to have two such
tables, one for color and the other for mono, and send one of
them to TPPDMENU based on the current display mode. The
ColorTable is of type MenuAttributeArray and has the following
form:
TextColor, {Normal menu color}
FrameColor, {Menu frame color}
SelectColor, {Selected menu item color}
HighLightColor {Highlighted selection character in menu}
MenuAttributeArray = array[ColorType] of Byte;
UserDefindedHelpPtr is used to pass the address of a routine to
be invoked when F1 is pressed. If you aren't using this feature
pass nil in its place. It is a generic pointer type which is
"absoluted" to a global variable of UserHelpType and should be of
the form:
{$F+}
Procedure(OptionIndex : Integer);
{$F-}
UserDefinedValidationPtr is used to pass the address of a routine
to validate a user's access to a particular menu option. Using
this routine, you can allow access to some routines, while not
allowing others. For instance, you might not want to give the
user access to the Edit option until he has selected the Open
option. Routines that are accessible will have their trigger
keys (usually the first key) highlighted and will allow the user
to move the selection bar to them. Routines that are not
accessible will not have their trigger key highlighted, nor will
the user be able to move the selection key to them. If you are
not using this option pass a nil value to it. It is a generic
pointer type which is "absoluted" to a global variable of
UserValidationType and should be of the form:
{$F+}
Function(OptionIndex : Integer) : boolean;
{$F-}
UserDefinedEvaluatePtr is used to evaluate a given menu item's
status. You may have an option that is, say, a toggle. Its
status is associated with a particular boolean variable. You
could use this routine to either display ON or OFF beside the
text of the menu item in order to show its status. If you are
not using this option, pass a nil in its place. It is a generic
pointer type which is "absoluted" to a global variable of
UserEvaluateType and should be of the form:
{$F+}
Procedure(C : Integer; Stat : Byte; var S : String);
{$F-}
UserDefinedExitMenusPtr is used to determine which options
selected actually cause the menu system to be exited and which
ones keep the menu system on the screen. Often the only option
which should have the menus exited is the Quit or Exit option
itself, depending on your application. If you are building an
editor, and you have an option that turns block marking on such
that moving the cursor marks the block, of course you would exit,
so the user could move the cursor in your editor. If you do not
intend to use this option, pass a nil value in its place. It is
a generic pointer type which is "absoluted" to a global variable
of UserValidationType and should be of the form:
{$F+}
Function(OptionIndex : Integer) : boolean;
{$F-}
BuiltInMenuAddress is used to point to the area of memory where
the menu data is located. This option is exclusive of the
Menuname option. If you pass the Menuname option, you may not
pass this one (it will have no effect) and if you pass this
option you should pass an empty string for the Menuname.
Essentially, this option's primary use is to bind the menu data
file into your .EXE. The process is as follows: first create and
compile the menu data file as you would normally. You may want
to test the menu data file's contents while it is file-based and,
once it is satisfactory, bind it to your .EXE. Secondly, use
Borland's BINOBJ utility to create an .OBJ that can be linked
into your code using the $L directive. The command line for
BINOBJ would be something like:
BINOBJ MDATA.MNU MDATA MYMENUS
MDATA.MNU is the name of the binary file to convert, MDATA is the
name of the .OBJ to create and MYMENUS is the name of the dummy
identifier that you may reference by address for TPPDMENU's
purposes. You could then call InitMenus with the following
parms:
InitMenus('',MenuColors,nil,nil,nil,nil,@MYMENUS);
The PUBLIC identifier, MYMENUS, created by BINOBJ, just gives us
something with which to reference the area of memory containing
the menu data.
A conditional define, called AllowHotKeys, allows you to have
keys which begin with a null (most special keys, such as the
function keys, and the Alt and Ctrl key combinations) to
essentially exit from the menu system to be processed by your
application. For instance, you could set up Alt-X to exit the
application. When Alt-X was pressed (with AllowHotKeys defined)
the menus would exit and would insert the key sequence for Alt-X
into the keyboard buffer. Your application could then read the
keyboard and determine that the user wanted to exit and then do
so.
Be sure to declare any of the procedure or function addresses you pass to
TPPDMENU as far using the $F+ compiler directive.
Here is a simple program which uses TPPDMENU:
{===============================================================}
{
TESTMENU.PAS
}
program Test;
{-Test pulldown menus}
uses
TpCrt, {screen routines - standard unit}
Dos, {dos calls - standard unit}
TpString, {string handling}
TpPdmenu; {pulldown menu interface}
var
choice : integer;
exitm : boolean;
Ch : char;
Attribs : MenuAttributeArray; {Currently selected attributes}
const
MonoAttr : MenuAttributeArray = {For mono systems}
(
$07, {TextColor}
$0F, {FrameColor}
$70, {SelectColor}
$0F {HighLightColor}
);
ColorAttr : MenuAttributeArray = {For color systems}
(
$70, {TextColor}
$78, {FrameColor}
$0F, {SelectColor}
$74 {HighLightColor}
);
begin {Test menus}
{-Initialize some variables}
choice := 0;
exitm := false; {-Is passed thru GetMenuChoice; must be set to True if
Hot keys are to be processed properly}
{-Set up color table}
case CurrentMode of
2, 7 :
Attribs:=MonoAttr;
else
Attribs:=ColorAttr;
end;
{-Initialize menu system with color set Attribs, no user help, no user
validation, no user special variable evaluation and no exit check}
if InitMenus('TEST.MNU',Attribs,nil,nil,nil,nil,nil) = 0 then
GetMenuChoice(choice,exitm);
{-Show the choice}
clrscr;
Writeln(choice);
ch:=readkey;
end. {Test menus}
{===============================================================}
Note that InitMenus returns a numeric value; if the value is
non-zero an error of some sort has occured. The posible return
values are:
Value Meaning
-1 Insufficient memory
-2 Root menu is not first in the menu data
-3 Too many submenus have been specified
-4 Level number is out of synch in menu data
-5 Error opening the menu data file
-6 Error reading the menu data file
Below is a sample menu data file. It appears a little confusing
at first, but is actually very simple.
{===============================================================}
*
* TEST.MSC
* MENU SOURCE FILE
* COMPILE WITH MAKEPMNU
*
*
*
*
************************ Main menu
*menulev, xposn, yposn, xsize, ysize, submax
1, 5, 4, 40, 1, 2
************************ Main menu selections
*command, dispoffset, special, selectoffset, string
255, 2, 0, 0, 'Install'
255, 11, 0, 0, 'Quit'
************************ Install menu
2, 6, 6, 23, 4, 4
255, 0, 0, 0, 'Keyboard'
1, 1, 0, 0, 'Switches'
2, 2, 0, 0, 'Colors'
255, 3, 0, 0, 'Macros...'
************************ Keyboard menu
3, 19, 8, 20, 2, 2
3, 0, 3, 0, 'Read'
4, 1, 0, 0, 'Edit'
************************ Switches menu (none, required as placeholder)
3, 1, 8, 10, 0, 0
************************ Colors menu (none, required as placeholder)
3, 1, 8, 10, 0, 0
************************ Macros menu
3, 19, 10, 20, 3, 3
5, 0, 3, 0, 'Read'
6, 1, 0, 0, 'Edit'
7, 2, 0, 0, 'Delete'
************************ Quit "menu"
2, 13, 6, 10, 1, 1
50, 0, 0, 0, 'Quit'
255
menulevel ─────┐
│ xposition │
│ │ yposition │
│ │ │ menuwidth ├─Header
│ │ │ │ menudepth │
│ │ │ │ │ maximum items │
│ │ │ │ │ │ │
2, 6, 6, 23, 4, 4 ─────┘
255, 0, 0, 0, 'Keyboard' ─────┐
1, 1, 0, 0, 'Switches' │
2, 2, 0, 0, 'Colors' │
255, 3, 0, 0, 'Macros...' │
│ │ │ │ │ │
│ │ │ │ itemtext ├─Body
│ │ │ │ │
│ │ │ trigger offset │
│ │ variabletype │
│ itemnumber │
│ │
commandorder ─────┘
Menu level : the level of the current menu. Levels start at 0 and can be
as high as 3. Each submenu is one level greater than its parent menu level.
HEADER:
Xposition : the horizontal position of this menu
Yposition : the vertical position of this menu
Menuwidth : the horizontal width of this menu
Menudepth : the vertical depth of this menu
Maxitems : the number of items on this menu
BODY:
Commandorder : the command number of the associate command or function.
Itemnumber : this menu option's order among the other menu options.
Variabletype : the type of the variable you wish to display next to this
option -- 0 for none, 1 for boolean (logical), 2 for
numeric and 3 for string. TPPDMENU passes this value to
your evaluator routine so that you may display a variables
value along side it on the menus. Leave the value set to
0 if you do not intend to display a value beside this menu
option.
Triggeroffset : is the offset, less one, where the trigger is located in
the Itemtext. In other words, if this option is set to
0, the trigger key is the first letter of the Itemtext
and so on
Itemtext : the actual text that composes a menu item. The first
character of a menu item is normally it's "trigger key" --
the key that causes it to be executed, no matter where you
happen to be in its particular menu.
Note items which have submenus to them are listed as Commandord 255. Also
note that the list ends with a lone 255, this is the EOM, or End of Menu
marker. Since there is no way to tie a particular submenu to a menu option,
it is done sequentially, that is, the first submenu following a menu is
associated with menu item 0, the second with menu item 1 and so on.
Therefore, if you wish to have options on the same menu which reference
submenus and others which do not, you will have to set up place holder or
filler menus. These are simply menus associated with a particular menu item
that does not actually have a submenu associated with it, but precedes one
that does. A filler menu need only be one line long and does actually contain
any menu items. The Switches and Colors submenus above are examples of such
menus. They do not actually represent submenus themselves, but are necessary
because we wish to place the Keyboard and Macro submenu options on opposite
ends of their parent menu, Install.
{===============================================================}
Compiling with MAKEPMNU
TPPDMENU menu files are compiled with a supplied utility MAKEPMNU. You may
distribute MAKEPMNU with your applications, if you like, so that your users
may customize their menus.
Using MAKEPMNU is easy, just pass it the name of the menu file to compile.
The menu source file extension defaults to .MSC and the menu object file
extension defaults to .MNU. Even with the biggest menu source
files, the compile should complete in a second or two.
MAKEPMNU test
{===============================================================}
Here are a few routines to serve as examples of those you might
pass to InitMenus:
{Here is one to be passed as an evaluator -- a routine to display
text along side a menu option}
{$F+}
procedure EvaluateMenuOpt(C : Integer; Stat : Byte; var S : String);
var
Ss : string;
begin
Ss := '';
case stat of {-status of three indicates a string}
3 : begin
case C of
3 : Ss := JustFileName(kbdin); {-Display the name of the keyboard
file that was read}
5 : Ss := JustFileName(MacroInFile); {-Display the name of the macro
file that was read}
end;
end;
end;
Move(Ss[1], S[Length(S)-Length(Ss)], Length(Ss));
end;
{Here is one to serve as a menu exit function -- it determines
whether the menus should be erased when a choice is made, or
whether they should be left active}
Function AllowExit(C : Integer): Boolean;
begin
AllowExit := false;
If C=50 then AllowExit:=True; {Only the Quit option exits the menus}
end;
{This routine determines whether a specific item is accesible
based on whether a variable has been initialized with a value yet}
Function AllowAccess(AccessIndex : Integer) : boolean;
begin
AllowAccess:=True;
case AccessIndex of
6,7 : if MacroInFile = '' then AllowAccess:=false;
{-Don't allow Editing or Deleting of macros unless some have been
loaded}
end;
end;
{===============================================================}
ToggleBooleanVal(var InBoolean : boolean);
ToggleBooleanVal allows you to force a toggle option to either ON
or OFF. When Space or BackSpace is pressed while in the menus
the global variable, ToggleBoolean, will be set to either 1,
when Backspace is pressed, to force it to OFF, or 2, when Space
is pressed, to force it to ON. The menus will then behave as
though Enter were pressed and your application should use
ToggleBooleanVal to toggle the boolean variable appropriately.
This would allow you to force a toggle to a particular value
without knowing its prior state, a feature handy in keyboard
macros. You can use ToggleBooleanVal to toggle the value whether
Space or Backspace or just the Enter key was pressed. If Space
or Backspace where not pressed (and, consequently
ToggleBoolean=0) the routine will simply toggle the value passed
to it.
{===============================================================}
>>>>>FEATURES NEW TO THIS RELEASE OF TPPDMENU
I have added mouse support with this release of TpPdMenu via the
TpPdMous unit. This unit requires TpMouse from TurboPower Software
and would actually add mouse support to any program, since it simply
translates mouse movements or pressed buttons into keys and pokes
them into the keyboard buffer via TpCrt.StuffKey. Currently, the
left button is the equivalent of pressing <Enter>, the right button
is the equivalent of pressing <Esc> and pressing both buttons is the
equivalent of pressing <F1>. You may set both the speed and the
default button-to-key translations by modifying TpPdMous.
That's about all there is to TPPDMENU. The source is provided to
both the unit and the compiler, keep in mind that you will need
Turbo Professional from TurboPower Software in order to use
TPPDMENU. You may extract the sample program and sample menu data
file here if you wish for testing the unit.
This unit is distributed as "freeware" and you are under no
obligation to me for using it. I only ask that you leave my
copyright notices in tact and that if you redistribute this
software (either by electronic or other means) you keep the
files here together and do not omit any of them.
Happy menuing!
Ken Henderson